Перейти к основному содержимому

Datasync между браузерами

· 4 мин. чтения

При постройке качественного single-page приложения рано или поздно встаёт вопрос синхронизации данных. Это тем более актуально, когда дело касается работы разных пользователей. Приложения типа google wave, google docs, push-notifications в IOS, подняли планку ожидания пользователей и от обычных веб-систем

Что даёт синхронизация

Увеличивает реактивность, поддерживая данные в реальном времени без обновления страницы. Типичная ситуация когда вы работаете в нескольких табах и данные не обновляются потому что закешировались

Улучшает безопасность — если пользователь выходит из одного таба, его можно выкинуть из остальных автоматически

Снижает нагрузку на сервер — можно высылать оповещение о состоянии файла, если он обрабатывается в реальном времени, подобно ютубу без какого-либо взаимодействия с пользователем или поллинга

Сложности реализации

Если вы решили что это must-have фича, прежде чем начать реализовывать её у себя, задумайтесь о последствиях:

  • Вам понадобится транспортный механизм (см. ниже), который обычно ограничен количеством подключённых пользователей (макс. 10 тыс), размером сообщения и объёмом траффика
  • Безопасность. Транспортный механизм и источник оповещения должен точечно высылать данные только нужному пользователю (без broadcast-а).
    Лучше всего источник оповещения ставить на backend, сразу после закрытия транзакции. В этом случае полезно привязываться к сессии на бэкэнде
  • Я советую не использовать datasync-сервис в качестве источника данных. Это должен быть легковесный вестник адреса по которому можно прочитать детали. Более того, формат этого сообщения должен быть стандартизирован. Например {action:'file.added', id:1345}
  • Весь front-end код должен хранить данные в сыром виде в сервисах/моделях, которые будут точечно обновляться.
    Соответсвенно все события будут делится на прямое вмешательство пользователя и на datasync-действия
    Код при этом будет запускать похожие функции над данными
  • Все use-кейсы усложняются из-за ситуаций 
    • что делать если A удалил данные который B просматривает (редиректить B, блокировать A, показывать оповещение B?)
    • что делать если A и B одновременно сохраняют изменения над одним и тем же обьектом (провести обе операции, кто последний тот и победил? провести первую и заблокировать последующие до окончания операции?)
    • что делать если A составляет новый обьект 3, ссылающийся на обьект 2, который удаляет B, а потом происходит сохранение (удалять include при удалении или при сохранении?)
  • Если вы используете систему привилегий, то надо дополнительно иметь оповещения о присвоении или изъятия обьекта из видимости пользователей
  • Если ваш сервис синхронизации вдруг упадёт, то при поднимании надо сделать так что-бы сообщения не потерялись из-за ещё неподключившихся пользователей (у socket.io 5 сек)

Polling

Не ушёл в небытие, я по-прежнему вижу как некоторые сайты настойчиво стучат в бэкэнд. Например движение общественного транспорта в Таллинне. Видимо это проще всего реализовать и проще всего использовать вместо API. Что может быть проще для сторонних разработчиков - просто читай .json файл так часто как тебе это надо. А он в свою очередь может выплёвываться из кэша-в-памяти

Pusher

Пушер — сервис который вобщем-то следующий по сложности для разработчиков. Внедряете скрипт, подписываетесь на события в js. Высылаете события, которые будут получать все пользователи.

Лучше всего это делать на уровне backend'а, иначе захламите frontend и могут возникнуть редкие баги. Например — поставил заливаться файл и закрыл браузер, а клиент X не получил итогового оповещения. Для более тонкой настройки прийдётся повозиться с интеграцией авторизации и токенами

Firebase

Наконец, ещё один сервис, купленный гуглом, который больше позиционируется как nosql-база данных с синхронизацией между клиентами. Для того что-бы настроить её, как систему оповещений, но при этом оставить хранение данных у себя, прийдётся повозиться. Изначальный setup такой же простой как у pusher'а, да и авторизация по токену такая же, но поскольку это БД, то подписываться надо не на события оповещений, а на изменения json-схемы. Саму json-схему вы делаете сами, но я советую для этого случая использовать что-то типа..

{
notifications:[
2345:[
'file X added by 2346',
'file Y deleted by 2346'
],
2346:[
'file X added by 2345'
]
]
}

Websocket-сервер / Socket.io

Socket.io вы должны хостить сами и для этого нужен nodejs. Socket.io реализует браузерные веб-сокеты, протокол которых менялся несколько раз. Из-за этого могут быть трудности с подключением со стороны php к нему. Я использую elephant.io, пока полёт нормальный. Самый простой начальный вариант —  socket.io принимает подключение и делает broadcast всем подключённым клиентам. Для более тонкой настройки прийдётся повозиться с куки, php сессиями и желательно переносом их хранения в БД, что-бы backend мог высылать безопасно сообщение конкретному подключённому пользователю, после чего контролировать по session_id + socket кто что будет получать.

У socket.io есть альтернативные библиотечки — socky (любит руби), sockJs, вроде как очень быстрый wsengine.iodata.ioFaye я сам не пробовал, но судя по описанию растёт ещё со времени когда терминология с кометами была на слуху. Видимо теперь тоже работает на веб-сокетах